/**
 * @file riscv.h
 * @date 23.04.25
 * @author xin
 * @brief 操作riscv底层结构的一系列函数和数据结构
 * @version 0.1
 * @status Stable
*/

#ifndef __ASSEMBLER__
#define __ASSEMBLER__

/**
 * @brief 读取内核id
 * @return 当前运行的内核id
*/
static inline uint64
r_mhartid()
{
    uint64 x;
    __asm__ volatile("csrr %0, mhartid" : "=r" (x) );
    return x;
}


/* mstatus */
// MPP位
#define MSTATUS_MPP_MASK    (3L << 11) 
#define MSTATUS_MPP_M       (3L << 11)
#define MSTATUS_MPP_S       (1L << 11)
#define MSTATUS_MPP_U       (0L << 11)

#define MSTATUS_MIE         (1L << 3)   // MIE位：使能M中断
#define MSTATUS_SIE         (1L << 1)   // SIE位：使能S中断
#define MSTATUS_MPIE        (1L << 7)   // MPIE位：M中断使能保存位
#define MSTATUS_SPIE        (1L << 5)   // SPIE位：S中断使能保存位

/**
 * @brief 读取mstatus值
 * @return 当前的mstatus值
*/
static inline uint64
r_mstatus()
{
    uint64 x;
    __asm__ volatile("csrr %0, mstatus" : "=r"(x) );
    return x;
}

/**
 * @brief 将x写入mstatus
 * @param x 待更新的mstatus值
*/
static inline void
w_mstatus(uint64 x)
{
    __asm__ volatile("csrw mstatus, %0" : : "r" (x));
}

/* mepc：M模式处理完异常后返回的指令地址 */

/**
 * @brief 将x写入mepc
 * @param x 异常处理完成后的返回地址
*/
static inline void 
w_mepc(uint64 x)
{
    __asm__ volatile("csrw mepc, %0" : : "r" (x));
}

/* status */
#define SSTATUS_SPP     (1L << 8)   // SPP位：1=S，0=U
#define SSTATUS_SPIE    (1L << 5)   // SPIE位：S中断使能保存位
#define SSTATUS_UPIE    (1L << 4)   // UPIE位：U中断使能保存位
#define SSTATUS_SIE     (1L << 1)   // SIE位：使能S中断
#define SSTATUS_UIE     (1L << 0)   // UIE位：使能U中断

/**
 * @brief 读取sstatus值
 * @return 当前的sstatus值
*/
static inline uint64
r_sstatus()
{
    uint64 x;
    __asm__ volatile("csrr %0, sstatus" : "=r"(x) );
    return x;
}

/**
 * @brief 将x写入sstatus
 * @param x 待更新的sstatus值
*/
static inline void 
w_sstatus(uint64 x)
{
    __asm__ volatile("csrw sstatus, %0" : : "r" (x));
}

/* sip：哪些中断处于pending状态 */

/**
 * @brief 读取sip，获取当前pending的中断
 * @return sip值
*/
static inline uint64
r_sip()
{
    uint64 x;
    __asm__ volatile("csrr %0, sip" : "=r"(x) );
    return x;
}

/**
 * @brief 将x写入sip，更新pending的中断
 * @param x 待更新的sip值
*/
static inline void
w_sip(uint64 x)
{
    __asm__ volatile("csrw sip, %0" : : "r" (x));
}

/* sie：控制S模式中断使能 */
#define SIE_SEIE    (1L << 9)   // SEIE位：外部中断
#define SIE_STIE    (1L << 5)   // STIE位：计时器中断
#define SIE_SSIE    (1L << 1)   // SSIE位：软件中断

/**
 * @brief 读取sie值，获取当前s使能的中断
 * @return sie值 
*/
static inline uint64
r_sie()
{
    uint64 x;
    __asm__ volatile("csrr %0, sie" : "=r"(x) );
    return x;
}

/**
 * @brief 将x值写入sie，更新S使能的中断
 * @param x 待更新的sie值
*/
static inline void
w_sie(uint64 x)
{
    __asm__ volatile("csrw sie, %0" : : "r" (x));
}

/* mie：控制M模式中断使能*/
#define MIE_MEIE    (1L << 11)   // MEIE位：外部中断
#define MIE_MTIE    (1L << 7)   // MTIE位：计时器中断
#define MIE_MSIE    (1L << 3)   // MSIE位：软件中断

/**
 * @brief 读取mie，获取M已使能的中断
 * @return mie值
*/
static inline uint64
r_mie()
{
    uint64 x;
    __asm__ volatile("csrr %0, mie" : "=r" (x) );
    return x;
}

/**
 * @brief 将x写入mie，更新使能的中断
 * @param x 待更新的mie值
*/
static inline void
w_mie(uint64 x)
{
    __asm__ volatile("csrw mie, %0" : : "r" (x));
}

/* sepc：S模式处理完异常后返回的指令地址*/

/**
 * @brief 读取sepc值，获取S异常处理完成后的返回地址
 * @return sepc值
*/
static inline uint64
r_sepc()
{
    uint64 x;
    __asm__ volatile("csrr %0, sepc" : "=r"(x) );
    return x;
}

/**
 * @brief 将x写入sepc，更新异常处理完成后的返回地址
 * @param x 待更新的sepc值
*/
static inline void
w_sepc(uint64 x)
{
    __asm__ volatile("csrw sepc, %0" : : "r" (x));
}

/* medeleg：M模式异常委托，决定哪些异常可以委托给低特权级 */

/**
 * @brief 读取medeleg，获取可以委托的异常类型
 * @return medeleg值
*/
static inline uint64
r_medeleg()
{
    uint64 x;
    __asm__ volatile("csrr %0, medeleg" : "=r"(x) );
    return x;
}

/**
 * @brief 将x写入medeleg，更新可以委托的异常类型
 * @return 待更新的medeleg值
*/
static inline void
w_medeleg(uint64 x)
{
    __asm__ volatile("csrw medeleg, %0" : : "r" (x));
}

/* mideleg：M模式中断委托，决定哪些中断可以委托给低特权级 */

/**
 * @brief 读取mideleg值，获取可以委托的中断类型
 * @return mideleg值
*/
static inline uint64
r_mideleg()
{
    uint64 x;
    __asm__ volatile("csrr %0, mideleg" : "=r"(x) );
    return x;
}

/**
 * @brief 将x写入mideleg，更新可以委托的异常类型
 * @param x 待更新的mideleg值
*/
static inline void 
w_mideleg(uint64 x)
{
    __asm__ volatile("csrw mideleg, %0" : : "r" (x));
}

/* stvec：S模式异常向量表入口地址和异常访问模式 */

/**
 * @brief 读取stvec，获取异常向量表入口地址和异常访问模式
 * @return stvec值
*/
static inline uint64
r_stvec()
{
    uint64 x;
    __asm__ volatile("csrr %0, stvec" : "=r"(x) );
    return x;
}

/**
 * @brief 将x写入stvec，更新异常向量表入口地址和异常访问模式
 * @param x 待更新的stvec值
*/
static inline void 
w_stvec(uint64 x)
{
    __asm__ volatile("csrw stvec, %0" : : "r" (x));
}

/* mtvec：M模式异常向量表入口地址和异常访问模式 */

/**
 * @brief 将x写入mtvec，更新异常向量表入口地址和异常访问模式
 * @param x 待更新的mtvec值
*/
static inline void 
w_mtvec(uint64 x)
{
  __asm__ volatile("csrw mtvec, %0" : : "r" (x));
}

/* pmpcfg0 & pmpadd0：PMP配置寄存器和地址寄存器 */

/**
 * @brief 将x写入pmpcfg0，更新pmp配置
 * @param x 待更新的pmpcfg0值
*/
static inline void
w_pmpcfg0(uint64 x)
{
    __asm__ volatile("csrw pmpcfg0, %0" : : "r" (x));
}

/**
 * @brief 将x写入pmpaddr0，更新pmp地址
 * @param x 待更新的pmp初始地址
*/
static inline void
w_pmpaddr0(uint64 x)
{
    __asm__ volatile("csrw pmpaddr0, %0" : : "r" (x));
}

/* satp：地址转换和保护寄存器 */
// MODE位
#define SATP_MASK   (0xF << 60)
#define SATP_SV39   (8L << 60)
#define SATP_SV48   (9L << 60)

// 默认设置当前页表pagetable为Sv39方案
#define MAKE_SATP(pagetable) ( SATP_SV39 | (((uint64)pagetable) >> 12) )
// 设置当前页表pagetable为Sv48方案
#define MAKE_SV48(pagetable) ( SATP_SV48 | (((uint64)pagetable) >> 12) )

/**
 * @brief 读取satp，获取地址转换模式和一级页表PPN
 * @return satp值
*/
static inline uint64
r_satp()
{
    uint64 x;
    __asm__ volatile("csrr %0, satp" : "=r"(x) );
    return x;
}

/**
 * @brief 将x写入satp，更新地址转换模式和一级页表PPN
 * @param x 待更新的satp值
*/
static inline void
w_satp(uint64 x)
{
    __asm__ volatile("csrw satp, %0" : : "r" (x));
}

/* mscratch：在当前模式在低特权模式时，保存M模式的上下文信息*/

/**
 * @brief 读取mscratch值，M模式时获取M模式的上下文信息的地址
 * @return mscratch值
*/
static inline uint64
r_mscratch()
{
    uint64 x;
    __asm__ volatile("csrr %0, mscratch" : "=r"(x) );
    return x;
}

/**
 * @brief 将x写入mscratch，退出M模式时更新M模式的上下文信息的地址
 * @param x 待更新的mscratch值
*/
static inline void
w_mscratch(uint64 x)
{
    __asm__ volatile("csrw mscratch, %0" : : "r" (x));
}

/* scause：S模式记录trap发生原因*/

/**
 * @brief 读取scause，获取trap发生原因
 * @return scause值
*/
static inline uint64
r_scause()
{
    uint64 x;
    __asm__ volatile("csrr %0, scause" : "=r"(x) );
    return x;
}

/* stval：S模式记录发生trap的地址*/
/**
 * @brief 读取stval，获取trap发生地址
 * @return stval值
*/
static inline uint64
r_stval()
{
    uint64 x;
    __asm__ volatile("csrr %0, stval" : "=r"(x) );
    return x;
}

/* mcounteren：使能S模式或U模式的硬件性能监测和计数寄存器 */

/**
 * @brief 将x写入mcounteren，更新S或U的硬件性能检测和计数寄存器的使能情况
 * @param x 待更新的mcounteren值
*/
static inline void
w_mcounteren(uint64 x)
{
    __asm__ volatile("csrw mcounteren, %0" : : "r" (x));
}

/**
 * @brief 读取mcounteren值，获取S或U的硬件性能检测和计数寄存器的使能情况
 * @return mcounteren值
*/
static inline uint64
r_mcounteren()
{
    uint64 x;
    __asm__ volatile("csrr %0, mcounteren" : "=r"(x) );
    return x;
}

/* time：系统实际时间 */

/**
 * @brief 读取time值
 * @return 当前time值
*/
static inline uint64
r_time()
{
    uint64 x;
    __asm__ volatile("csrr %0, time" : "=r"(x) );
    return x;
}

/* 通用寄存器 */
/* sp */

/**
 * @brief 读取sp
 * @return sp值
*/
static inline uint64
r_sp()
{
    uint64 x;
    __asm__ volatile("mv %0, sp" : "=r"(x) );
    return x;
}

/* tp：本例用来存储内核id */

/**
 * @brief 读取tp值，存储的内核id
 * @return tp值
*/
static inline uint64
r_tp()
{
    uint64 x;
    __asm__ volatile("mv %0, tp" : "=r"(x) );
    return x;
}

/**
 * @brief 将当前的内核id值x写入tp
 * @param x 待更新的tp值
*/
static inline void 
w_tp(uint64 x)
{
    __asm__ volatile("mv tp, %0" : : "r" (x));
}

/* ra */

/**
 * @brief 读取ra值
 * @return ra值
*/
static inline uint64
r_ra()
{
    uint64 x;
    __asm__ volatile("mv %0, ra" : "=r"(x) );
    return x;
}

/**
 * @brief 使能S中断：SSTATUS_SIE=1
*/
static inline void 
intr_on()
{
    w_sstatus(r_sstatus() | SSTATUS_SIE);
}

/**
 * @brief 禁用S中断：SSTATUS_SIE=0
*/
static inline void 
intr_off()
{
    w_sstatus(r_sstatus() & ~SSTATUS_SIE);
}

/**
 * @brief 获取S中断使能状态，即SSTATUS_SIE位
 * @return SIE位是否为1
*/
static inline int
intr_get()
{
    return (r_sstatus() & SSTATUS_SIE) != 0;
}

/**
 * @brief 刷新TLB
*/
static inline void
sfence_vma()
{
    //zero, zero表示刷新所有TLB
    __asm__ volatile("sfence.vma zero, zero");
}

typedef uint64 pte_t;           // 页表项类型
typedef uint64 *pagetable_t;    // 页表指针，存着512个页表项

#endif

#define PGSIZE 4096 // 页表大小
#define PGSHIFT 12  // 页表偏移位数

#define PTE_V   (1L << 0)   // 该PTE是否有效
#define PTE_R   (1L << 1) 
#define PTE_W   (1L << 2)
#define PTE_X   (1L << 3)
#define PTE_U   (1L << 4)   // 该PTE用户是否能访问

// 通过物理地址得到PTE值
#define PA2PTE(pa) ((((uint64)(pa)) >> 12) << 10)
// 通过PTE值得到物理地址
#define PTE2PA(pte) (((pte) >> 10) << 12)
// 得到PTE的低10位的标志位，低到高分别是V, R, W, X, U, G(global), A(accessed), D(dirty)以及保留2位
#define PTE_FLAGS(pte) ((pte) & 0x3FF)

/* 提取出每一级的9位页表项索引 */

#define PXMASK          0x1FF           // 9位掩码
// 需右移位数
#define PXSHIFT(level)  ( PGSHIFT + (9*(level)) )
// 提取level级的PTE索引
#define PX(level, va)   ( (((uint64)(va)) >> PXSHIFT(level)) & PXMASK)

// 取上整 sz = (sz + 0xfff) & ~0xfff
#define PGROUNDUP(sz) ( ((sz) + PGSIZE - 1) & ~(PGSIZE-1) )
// 取下整 a = a & ~0xfff
#define PGROUNDDOWN(a) ( (a) & ~(PGSIZE-1) )


#define MAXVA   (1L << (9 + 9 + 9 + 12 - 1))        // 虚拟地址最大值，默认Sv39，空一位以防符号位
#define MAXVA_48 (1L << (9 + 9 + 9 + 9 + 12 - 1))    // Sv48虚拟地址最大值，空一位以防符号位
